Skip to content

feat: add the snapshot and dom tap commands for reading AUT DOM#34255

Closed
davidr-cy wants to merge 10 commits into
davidr/feat/tap-cli/tap-statusfrom
davidr/feat/tap-cli/tap-snapshots
Closed

feat: add the snapshot and dom tap commands for reading AUT DOM#34255
davidr-cy wants to merge 10 commits into
davidr/feat/tap-cli/tap-statusfrom
davidr/feat/tap-cli/tap-snapshots

Conversation

@davidr-cy

@davidr-cy davidr-cy commented Jul 8, 2026

Copy link
Copy Markdown
Contributor
  • Closes N/A — part of the experimental cypress tap CLI (internal dev tooling); no separate public issue.

Additional details

Adds two schema-driven cypress tap subcommands that let an agent read the app-under-test's DOM straight from the command log, so failures can be diagnosed from the terminal:

  • tap snapshot <test> <command> — reads the DOM snapshot the driver captured for a command-log entry (the same snapshots the reporter shows on hover). Returns the page HTML, or with --selector just the matching elements; the element(s) the command acted on (the [data-cypress-el] subject); the before/after snapshot listing; and, with --styles, the page stylesheets. --at selects which snapshot; --max-chars caps the payload (default 30000, flags truncated).
  • tap dom [selector] — reads the AUT's current live document, for inspecting an interactive session.

Implementation notes:

  • Historical snapshots are read from the live runner via getSnapshotPropsForLog — the reporter's own hover seam — not getTestsState, whose serialization blacklists snapshots. The handler adopts the detached clone, reads outerHTML, and never mutates it, so it can't disturb the visible AUT.
  • test/command are positional params, not options: commander 6 stores options as properties, so an option named command clashes with its built-in command property.
  • Both commands cap returned HTML and every failure is a typed TapCommandError; a zero-count selector match is a result, not an error.
  • No CLI changes — the commands are discovered from the schema. knip.json gets per-file types ignores matching the existing tap convention.

Steps to test

Manual end-to-end (open mode, Chrome-family or Electron browser):

  1. Start an instance: node scripts/cypress.js open --project <project> --e2e --browser electron
  2. cypress tap run <spec>, then poll cypress tap status until it finishes.
  3. cypress tap tests → pick a failing test id; cypress tap commands --test <id> → pick a command id.
  4. cypress tap snapshot <test> <command> --selector '<css>' to inspect the DOM at that command; cypress tap dom '<css>' to inspect the live page.

Validated end-to-end against a real instance (Cypress 15.19.0): element-not-found, wrong-text assertion, and visibility-regression scenarios each diagnosed from the CLI, plus the full typed-error model.

How has the user experience changed?

No change to end-user-facing Cypress behavior — this is internal cypress tap developer tooling. Two new subcommands appear in cypress tap help when talking to a running instance.

PR Tasks

  • [na] Is there an associated issue with maintainer approval for PR submission?
  • Have tests been added/updated?
  • [na] Has a PR for user-facing changes been opened in cypress-documentation?
  • [na] Have API changes been updated in the type definitions?

Note

Medium Risk
Pinning programmatically mutates the live AUT DOM and coordinates runner/reporter snapshot state; frame commands depend on CDP against the runner page, but scope is internal tap tooling rather than public Cypress APIs.

Overview
Adds CLI-native dom, aria, and inspect subcommands that short-circuit before the schema-driven tap program and read the app-under-test over Chrome DevTools Protocol (isolated world + Accessibility/DOM), including AUT frame resolution by the runner’s Your project: iframe name.

Extends TapSession with client / sessionId so those frame extractors share the same CDP attach/retry path as binding calls. Help text and build-program list the frame commands for discovery; routing stays in runFrame.

Introduces the in-app pin tap command to render a command-log DOM snapshot into the live AUT (capture/restore via the AUT iframe, native runner pin UI, stale-pin reconciliation on re-run/spec switch). run-state / cypress tap status now include pinned, and the reporter syncs when pin is driven from tap (snapshotPinned / reporter:snapshot:pinned).

Tests cover frame extractors, pin behavior, and updated CLI program registration; knip ignores new export-only types.

Reviewed by Cursor Bugbot for commit 9bb4a60. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread packages/app/src/tap/commands/snapshot.ts Outdated
@cypress

cypress Bot commented Jul 8, 2026

Copy link
Copy Markdown

cypress    Run #72423

Run Properties:  status check failed Failed #72423  •  git commit 9bb4a605ef: fix: adapt the tap pin command to the attempt-based test-state helpers
Project cypress
Branch Review davidr/feat/tap-cli/tap-snapshots
Run status status check failed Failed #72423
Run duration 11m 59s
Commit git commit 9bb4a605ef: fix: adapt the tap pin command to the attempt-based test-state helpers
Committer David Rowe
View all properties for this run ↗︎

Test results
Tests that failed  Failures 7
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 854
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 7726
View all changes introduced in this branch ↗︎

Warning

Partial Report: The results for the Application Quality reports may be incomplete.

UI Coverage  52.46%
  Untested elements 29  
  Tested elements 32  
Accessibility  98.9%
  Failed rules  0 critical   3 serious   1 moderate   0 minor
  Failed elements 18  

Tests for review

Failed  memory/memory.cy.js • 0 failed tests • 5x-driver-electron

View Output

Test Artifacts
Failed  memory/dom-stress-test.cy.js • 0 failed tests • 5x-driver-electron

View Output

Test Artifacts
Failed  commands/actions/type_special_chars.cy.ts • 0 failed tests • 5x-driver-electron

View Output

Test Artifacts
Failed  commands/querying/querying.cy.ts • 0 failed tests • 5x-driver-electron

View Output

Test Artifacts
Failed  e2e/origin/cookie_behavior.cy.ts • 0 failed tests • 5x-driver-electron

View Output

Test Artifacts

The first 5 failed specs are shown, see all 1024 specs in Cypress Cloud.

Comment thread cli/lib/tap/frame/index.ts
Comment thread packages/app/src/tap/commands/snapshot-pin.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 78fb9cb to 8ed2606 Compare July 10, 2026 01:20
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from ab6bd03 to a4e16ac Compare July 10, 2026 01:20
Comment thread cli/lib/tap/aut-frame.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from a4e16ac to ddcd8ac Compare July 10, 2026 15:05
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 8ed2606 to 92dbaba Compare July 10, 2026 15:05
Comment thread packages/app/src/tap/commands/pin.ts
Comment thread packages/app/src/tap/commands/snapshot-pin.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from ddcd8ac to a209a74 Compare July 10, 2026 15:13
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 92dbaba to 19f7898 Compare July 10, 2026 15:13
Comment thread packages/app/src/tap/commands/pin.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from a209a74 to c196607 Compare July 10, 2026 19:12
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 19f7898 to 07941de Compare July 10, 2026 19:12
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from c196607 to 934ad77 Compare July 13, 2026 14:19
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 07941de to 7647a01 Compare July 13, 2026 14:19
Comment thread packages/app/src/tap/commands/pin.ts
Comment thread packages/app/src/tap/commands/pin.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 7647a01 to 9bc0eb3 Compare July 13, 2026 15:11
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from 934ad77 to 52c822d Compare July 13, 2026 15:11
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 9bc0eb3 to 1177708 Compare July 13, 2026 16:48
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from 52c822d to 7d67ba1 Compare July 13, 2026 16:48
Comment thread packages/app/src/tap/commands/pin.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from 7d67ba1 to d808bce Compare July 13, 2026 19:29
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 1177708 to f3c2f7c Compare July 13, 2026 19:29
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from d808bce to f1fdd7e Compare July 14, 2026 19:20
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from f3c2f7c to 89052b5 Compare July 14, 2026 19:20
Comment thread packages/app/src/tap/commands/run-state.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from f1fdd7e to 1fd0a79 Compare July 15, 2026 20:04
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 89052b5 to 0128a8e Compare July 15, 2026 20:04

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1fd0a79. Configure here.

Comment thread packages/app/src/tap/commands/pin.ts
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from 0128a8e to ff64dbc Compare July 15, 2026 20:22
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from 1fd0a79 to fe13d7e Compare July 15, 2026 20:22
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from ff64dbc to d51d9fb Compare July 16, 2026 04:04
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch 2 times, most recently from 11ea87a to 79a7e42 Compare July 16, 2026 13:30
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch from d51d9fb to 4b3a0fd Compare July 16, 2026 13:30
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from 79a7e42 to 7c7484c Compare July 16, 2026 16:39
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-status branch 2 times, most recently from 41633c7 to 9b9b0cc Compare July 16, 2026 18:28
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from 7c7484c to f307c6a Compare July 16, 2026 18:28
davidr-cy added 10 commits July 16, 2026 13:42
Two schema-driven subcommands let an agent inspect the app under test:

- `snapshot <test> <command>` reads the DOM snapshot the driver captured
  for a command-log entry — the same snapshots the reporter shows on
  hover. It returns the page HTML (or, with --selector, just the matching
  elements), the element(s) the command acted on (the [data-cypress-el]
  subject), the before/after snapshot listing, and optionally the page
  stylesheets. Reads the live runner via getSnapshotPropsForLog rather
  than getTestsState, whose serialization blacklists snapshots.

- `dom [selector]` reads the AUT's current live document for interactive
  inspection.

Both cap returned HTML at a character budget (default 30000) and flag
truncation, so an unscoped read of a heavy page can't flood the caller.
Test and command ids are positional params on snapshot: commander 6
stores options as properties, so an option named `command` clashes with
its built-in `command` property.
…mands

Reads the app-under-test DOM directly over CDP instead of serializing it
in the runner page:

- Removes the app-side `snapshot` and `dom` tap commands (and their
  helpers/specs). Historical DOM will come from pinning a command (next),
  and live DOM now comes from CDP.
- Extends `withTapSession` to expose the attached CDP client + session so
  extractors can run Page/DOM/CSS/Accessibility against the AUT frame.
- Adds `resolveAutFrame`: the AUT is a same-process child frame of the
  runner page (name `Your project: '<name>'`) — verified empirically to
  be a child frame, not an OOPIF, so one attached session reaches it.
- Adds the CLI-native `tap frame` command group and `frame dom`, which
  reads the current AUT DOM (whole page or a selector's matches) via an
  isolated world, capping output browser-side.

`frame ax`, `frame inspect`, and the binding `pin` command follow. The
frozen getSchema/exec contract is unchanged; `frame` is CLI-native.
`cypress tap frame ax [selector]` returns the app-under-test's
accessibility tree — roles, names, values, and key states — from
Accessibility.getFullAXTree scoped to the AUT frame, projected to a
compact indented tree (noise roles collapsed, ignored nodes dropped)
with a --max-nodes cap. A selector roots the read at a subtree by
matching the element's backend node id; a non-matching selector is an
empty result, a malformed one is INVALID_SELECTOR.
`cypress tap pin <test> <command> [--at]` renders a command's captured
DOM snapshot into the live app-under-test frame (via the reporter's
restore path), so the CDP `tap frame` commands can read that historical
moment — its HTML, accessibility tree, computed styles — deterministically
instead of whatever the live frame happens to show. `pin --clear` restores
the pre-pin DOM; it is idempotent.

The pin is app state that persists between tap calls (each CLI call is a
fresh CDP connection, so no handle crosses them). Guards: NO_RUN,
RUN_IN_PROGRESS, ALREADY_PINNED (one pin at a time), TEST_NOT_FOUND,
COMMAND_NOT_FOUND, SNAPSHOT_UNAVAILABLE, SNAPSHOT_NOT_FOUND. The snapshot
store's pinned flag is set so the reporter's hover machinery can't clobber
the pinned DOM.
- `cypress tap frame inspect <selector>` returns one element's tag,
  attributes, curated computed styles, box rect, and accessibility node.
  It reads the element's info in an isolated world (getComputedStyle /
  getBoundingClientRect on the element) and takes only the AX node from
  CDP — avoiding the brittle requestNode/nodeId path.
- `run-state` (and therefore `status`) now reports the currently pinned
  command, so a pin is always visible and a stranded one is recoverable.
Align with Playwright's naming for the accessibility tree (its ariaSnapshot
/ toMatchAriaSnapshot API and the "aria snapshot" its agent tooling
returns). `tap frame ax` becomes `tap frame aria`; the extractor, its
result types, and the per-element accessibility field on `frame inspect`
follow suit. CDP protocol identifiers (AXNode, getFullAXTree) keep their
names.
A pin leaked across spec switches and re-runs: the module-level pin state
survived, so `status` kept reporting a pin that no longer existed and a
`pin --clear` could restore a stale snapshot over the new run's DOM.

Reconcile the pin against the current run before every pin/status/clear:
the pin is live only while the exact snapshot object it rendered is still
the command's current snapshot. A re-run re-captures fresh objects (even
when the log id is reused) and a spec switch drops the command entirely —
both fail the identity check, so the stale pin is released without
restoring its now-gone DOM.
Route the pin through the app's native pin so the AUT shows the pinned banner/controls and the reporter command log reflects it — the pinned command highlights and its test opens (mirrors the existing unpin notification). Re-pinning the same command with a new --at now moves the pin to that snapshot in place instead of erroring ALREADY_PINNED; a different command still requires a clear first.
@davidr-cy
davidr-cy force-pushed the davidr/feat/tap-cli/tap-snapshots branch from f307c6a to 9bb4a60 Compare July 16, 2026 18:43
@davidr-cy davidr-cy closed this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant